#include<bits/stdc++.h>
using namespace std;

struct stud_node{
    int id;
    char name[20];
    float score[3];
    float total;
    float average;
    struct stud_node *next;
};
//?????? 
void displaymenu(){
    printf("|------<????????????>------|\n");
    printf("|--------1:??????????--------|\n");
    printf("|--------2:?????????--------|\n");
    printf("|--------3:?????????--------|\n");
    printf("|--------4:?????????--------|\n");
    printf("|--------5:??????????--------|\n");
    printf("|--------6:?????????--------|\n");
    printf("|-----7:??????????????-----|\n");
    printf("|------------0:???------------|\n");
    printf("|------------------------------|\n");
    printf("|----------?????????:---------|\n");
}

//?????????
void displayquerymenu() {
    printf("|------<?????????>------|\n");
    printf("|-------1:???????-------|\n");
    printf("|-------2:?????????-------|\n");
    printf("|-------0:?????????-------|\n");
    printf("|--------------------------|\n");
    printf("|--------?????????:-------|\n");
}

//??????? 
stud_node * Create_Stu_Doc(){
    stud_node* head=(stud_node*)malloc(sizeof(stud_node));
    if(head==NULL){
        printf("???????????");
        exit(1); 
    }
    head->next=NULL;
    return head;
}
//???????
float calculatetotal(float* score){
    float total=0;
    for(int i=0;i<3;i++){
        total+=score[i];
    }
    return total;
}
//?????????
float calculateaverage(float total){
    return total/3;
} 
//?????????? 
stud_node * InsertDoc(stud_node * head) {
    stud_node* new_stud=(stud_node*)malloc(sizeof(stud_node));
    if(new_stud==NULL){
        printf("??????????\n");
        return head;
    }
    printf("????????? ???? ?????? ?????? ??????:\n");
    scanf("%d %s", &new_stud->id, new_stud->name);
    for(int i=0;i<3;i++){
        scanf("%f", &new_stud->score[i]);
    }
    for(int i=0;i<3;i++){
        if(new_stud->score[i]<0||new_stud->score[i]>100){
            if(i==0) printf("????");
            else if(i==1) printf("???"); 
            else printf("???"); 
            printf("??????0-100?????????????:");
            scanf("%f", &new_stud->score[i]);
        }
    }
    new_stud->total=calculatetotal(new_stud->score);
    new_stud->average=calculateaverage(new_stud->total);
    new_stud->next=NULL;

    stud_node* p=head;
    stud_node* q=head->next;
    while(q!=NULL&&q->id<new_stud->id){
        p=q;
        q=q->next;
    }
    new_stud->next=q;
    p->next=new_stud;
    printf("????????\n");
    return head;
}
//????????? 
stud_node * DeleteDoc(stud_node * head, int id){
    stud_node* p=head;
    stud_node* q=head->next;
    while(q!=NULL&&q->id!=id){
        p=q;
        q=q->next;
    }
    if(q!=NULL){
        p->next=q->next;
        free(q);
        printf("?????? %d ?????\n", id);
    }else{
        printf("????????? %d ???????\n", id);
    }
    return head;
} 
//?????????
stud_node * UpdateDoc(stud_node * head, int id){
    stud_node* p=head->next;
    while(p!=NULL&&p->id!=id){
        p=p->next;
    }
    if(p!=NULL){
        printf("??????:%d ????:%s\n", p->id, p->name);
        printf("?????????????????? ???? ?????? ?????? ??????:");
        scanf("%s", p->name); 
        for(int i=0;i<3;i++){
            scanf("%f", &p->score[i]);
        }
        for(int i=0;i<3;i++){
            if(p->score[i]<0||p->score[i]>100){
                if(i==0) printf("????");
                else if(i==1) printf("???"); 
                else printf("???"); 
                printf("??????0-100?????????????:");
                scanf("%f", &p->score[i]);
            }
        }
        p->total=calculatetotal(p->score);
        p->average=calculateaverage(p->total);
        printf("???????"); 
    }else{
        printf("????????? %d ???????\n", id);
    }
    return head;
}
//?????????
void PrintDoc(stud_node * head){
    if(head->next==NULL){
        printf("???????????\n");
        return; 
    }
    int count=0;
    stud_node* p=head->next;
    while(p!=NULL){
        count++;
        p=p->next;
    }
    stud_node** students=(stud_node**)malloc(count*sizeof(stud_node*));
    if(students==NULL){
        printf("??????????\n");
        return;
    }
    p=head->next;
    for(int i=0;i<count;i++){
        students[i]=p;
        p=p->next;
    }
    for(int i=0;i<count-1;i++){
        for(int j=0;j<count-i-1;j++){
            if(students[j]->total<students[j+1]->total){
                stud_node* temp=students[j];
                students[j]=students[j+1];
                students[j+1]=temp;
            }
        }
    }
    printf("\n%-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", "???", "????", "????", "???", "???", "???", "?????");
    printf("-------------------------------------------------------------------------\n");
    for(int i=0;i<count;i++){
        printf(" %-9d %-10s %-10.2f %-10.2f %-10.2f %-10.2f %-10.2f\n",
        students[i]->id, students[i]->name, students[i]->score[0],
        students[i]->score[1], students[i]->score[2], students[i]->total, students[i]->average);
    }
    free(students);
}
//?????????? 
void freelist(stud_node* head){
    stud_node* p=head;
    stud_node* q;
    while(p!=NULL){
        q=p;
        p=p->next;
        free(q);
    }
} 
//???????????????
void savestudents(stud_node * head, char *filename){
    if(head->next==NULL){
        printf("???????????????\n");
        return;
    }
    FILE* fp=fopen(filename,"wb"); //?????????????????
    if(fp==NULL){
        printf("????????:%s\n", filename);
        return;
    }
    stud_node* p=head->next;
    while(p!=NULL){
        fwrite(p, sizeof(stud_node), 1, fp); //?????????????????
        p=p->next;
    }
    fclose(fp);
    printf("????????? %s ????\n", filename);
}
//??????????????
stud_node * loadstudents(char *filename, int *count){
    FILE* fp=fopen(filename,"rb"); //?????????????????
    if(fp==NULL){
        printf("????????:%s\n ???????????????", filename);
        return Create_Stu_Doc();
    }
    stud_node* head=Create_Stu_Doc();
    stud_node* new_stud;
    *count=0;
    while(1){
        new_stud=(stud_node*)malloc(sizeof(stud_node));
        if(new_stud==NULL){
            printf("??????????\n");
            fclose(fp);
            freelist(head);
            exit(1);
        }
        if(fread(new_stud, sizeof(stud_node), 1, fp) != 1){ //????????????????
            free(new_stud);
            break;
        }
        new_stud->total=calculatetotal(new_stud->score);
        new_stud->average=calculateaverage(new_stud->total);
        new_stud->next=NULL;
        stud_node* p=head;
        stud_node* q=head->next;
        while(q!=NULL&&q->id<new_stud->id){
            p=q;
            q=q->next;
        }
        new_stud->next=q;
        p->next=new_stud;
        
        (*count)++;
    }
    fclose(fp);
    printf("????????:%s?????%d??????????\n", filename, *count);
    return head;
}

//???????
void queryid(stud_node * head, int id) {
    stud_node* p=head->next;
    while(p!=NULL&&p->id!=id){
        p=p->next;
    }
    if(p!=NULL){
        printf("\n%-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", "???", "????", "????", "???", "???", "???", "?????");
        printf("-------------------------------------------------------------------------\n");
        printf(" %-9d %-10s %-10.2f %-10.2f %-10.2f %-10.2f %-10.2f\n",
        p->id, p->name, p->score[0],
        p->score[1], p->score[2], p->total, p->average);
    }else{
        printf("????????? %d ???????\n", id);
    }
}

//????????????
void queryname(stud_node * head, const char *name) {
    stud_node* p=head->next;
    bool found = false;
    while(p!=NULL){
        if(strstr(p->name, name) != NULL) {
            if(!found) {
                printf("\n%-10s %-10s %-10s %-10s %-10s %-10s %-10s\n", "???", "????", "????", "???", "???", "???", "?????");
                printf("-------------------------------------------------------------------------\n");
            }
            printf(" %-9d %-10s %-10.2f %-10.2f %-10.2f %-10.2f %-10.2f\n", p->id, p->name, p->score[0], p->score[1], p->score[2], p->total, p->average);
            found = true;
        }
        p=p->next;
    }
    if(!found) {
        printf("????????????? %s ???????\n", name);
    }
}

//?????????
void querystudents(stud_node * head) {
    int querychoice;
    do {
        displayquerymenu();
        scanf("%d", &querychoice);
        switch(querychoice) {
            case 1: {
                int id;
                printf("???????????????: ");
                scanf("%d", &id);
                queryid(head, id);
                break;
            }
            case 2: {
                char name[20];
                printf("????????????????: ");
                scanf("%s", name);
                queryname(head, name);
                break;
            }
            case 0: {
                break;
            }
            default: {
                printf("???????????????????????????\n");
                break;
            }
        }
    } while(querychoice != 0);
}

int main(){
    int choice;
    int count=0;
    stud_node* head=Create_Stu_Doc();
    char filename[100];
    do{
        displaymenu();
        scanf("%d", &choice);
        switch(choice){
            case 1:
                head = InsertDoc(head);
                break;
            case 2: {
                int id;
                printf("?????????????????:");
                scanf("%d", &id);
                head = UpdateDoc(head, id);
                break;
            }
            case 3: {
                int id;
                printf("??????????????????:");
                scanf("%d", &id);
                head = DeleteDoc(head, id);
                break;
            }
            case 4:
                PrintDoc(head);
                break;
            case 5: {
                printf("???????????????????:");
                scanf("%s", filename);
                savestudents(head, filename);
                break;
            }
            case 6:
                querystudents(head);
                break;
            case 7: {
                printf("?????????????????:");
                scanf("%s", filename);
                head = loadstudents(filename, &count); 
                break;
            } 
            case 0:
                printf("??????????\n");
                freelist(head);
                break;
            default:
                printf("???????????????????????????\n");
                break;
        }
    } while(choice != 0);
    
    return 0;
}
